package com.starlinkdt.common.storage.impl;

import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.S3ClientOptions;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.S3Object;
import com.starlinkdt.common.storage.StorageInterface;
import com.starlinkdt.common.storage.config.NsccTjOssConfig;
import org.apache.poi.util.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 天河云对象存储
 *
 * @author system
 */
@Component
public class NsccTjOssImpl implements StorageInterface {
    @Autowired
    private NsccTjOssConfig nsccTjOssConfig;

    /**
     * 创建OSS实例
     *
     * @return NsccTjOss
     */
    private AmazonS3 generateClient() {
        AWSCredentials credentials = new BasicAWSCredentials(nsccTjOssConfig.getAccessKey(), nsccTjOssConfig.getSecretKey());
        AmazonS3 s3Client = new AmazonS3Client(credentials);
        s3Client.setEndpoint(nsccTjOssConfig.getEndpoint());
        s3Client.setS3ClientOptions(new S3ClientOptions().withPathStyleAccess(true));
        return s3Client;
    }

    /**
     * 关闭s3Client
     *
     * @param s3Client s3实例
     */
    private void close(AmazonS3 s3Client) {
        if (s3Client != null) {
            s3Client.shutdown();
        }
    }

    /**
     * 获取STS临时令牌
     *
     * @return Map
     */
    @Override
    public Map<String, Object> genStsToken() {
        Map<String, Object> ossMap = new HashMap<>(1);

        ossMap.put("securityToken", null);
        ossMap.put("accessKeyId", nsccTjOssConfig.getAccessKey());
        ossMap.put("accessKeySecret", nsccTjOssConfig.getSecretKey());
        ossMap.put("endpoint", nsccTjOssConfig.getEndpoint());
        ossMap.put("bucketName", nsccTjOssConfig.getBucketName());

        return ossMap;
    }

    /**
     * 上传Byte数组
     *
     * @param objectName 对象路径及名称
     * @param objectContent byte数组
     */
    @Override
    public void putObjectByte(String objectName, byte[] objectContent) throws IOException {
        // 创建s3Client实例。
        AmazonS3 s3Client = generateClient();

        try (InputStream inputStream = new ByteArrayInputStream(objectContent)) {
            // 上传Byte数组
            s3Client.putObject(nsccTjOssConfig.getBucketName(), objectName, inputStream, new ObjectMetadata());
        } finally {
            close(s3Client);
        }
    }

    /**
     * 上传网络流
     *
     * @param objectName 对象路径及名称
     * @param fileUrl 待上传的网络文件地址
     */
    @Override
    public void putObjectUrl(String objectName, String fileUrl) throws IOException {
        // 创建s3Client实例。
        AmazonS3 s3Client = generateClient();

        try (InputStream inputStream = new URL(fileUrl).openStream()) {
            s3Client.putObject(nsccTjOssConfig.getBucketName(), objectName, inputStream, new ObjectMetadata());
        } finally {
            close(s3Client);
        }
    }

    /**
     * 上传文件流
     *
     * @param objectName 对象路径及名称
     * @param filePath 待上传的本地文件路径,需要指定到具体的文件名
     */
    @Override
    public void putObjectFile(String objectName, String filePath) throws IOException {
        // 创建s3Client实例。
        AmazonS3 s3Client = generateClient();

        try (InputStream inputStream = Files.newInputStream(Paths.get(filePath))) {
            s3Client.putObject(nsccTjOssConfig.getBucketName(), objectName, inputStream, new ObjectMetadata());
        } finally {
            close(s3Client);
        }
    }

    /**
     * 判断文件是否存在
     *
     * @param objectName 对象路径及名称
     * @return boolean
     */
    @Override
    public boolean existObject(String objectName) {
        // 创建s3Client实例。
        AmazonS3 s3Client = generateClient();

        // 判断文件是否存在。如果返回值为true，则文件存在，否则存储空间或者文件不存在
        boolean found = s3Client.doesObjectExist(nsccTjOssConfig.getBucketName(), objectName);
        close(s3Client);

        return found;
    }

    /**
     * 获取签名URL
     *
     * @param objectName 对象路径及名称
     * @return String
     */
    @Override
    public String getObjectSignUrl(String objectName) {
        // 创建s3Client实例。
        AmazonS3 s3Client = generateClient();

        // 设置签名URL过期时间为3600秒（1小时）
        Integer oneThousand = 1000;
        Date expiration = new Date(System.currentTimeMillis() + nsccTjOssConfig.getDurationSeconds() * oneThousand);
        // 生成以GET方法访问的签名URL，访客可以直接通过浏览器访问相关内容。
        URL url = s3Client.generatePresignedUrl(nsccTjOssConfig.getBucketName(), objectName, expiration);

        // 关闭s3Client
        close(s3Client);

        return url.toString();
    }

    /**
     * 下载文件流
     *
     * @param objectName 对象路径及名称
     * @return byte
     */
    @Override
    public byte[] downloadObjectStream(String objectName) throws IOException {
        // 创建s3Client实例。
        AmazonS3 s3Client = generateClient();

        try {
            // s3Object包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
            S3Object s3Object = s3Client.getObject(nsccTjOssConfig.getBucketName(), objectName);
            InputStream inputStream = s3Object.getObjectContent();
            // 返回文件流
            return IOUtils.toByteArray(inputStream);
        } finally {
            close(s3Client);
        }
    }

    /**
     * 删除文件
     *
     * @param objectName 对象路径及名称
     */
    @Override
    public void deleteObject(String objectName) {
        // 创建s3Client实例。
        AmazonS3 s3Client = generateClient();

        // 删除文件或目录。如果要删除目录，目录必须为空。
        s3Client.deleteObject(nsccTjOssConfig.getBucketName(), objectName);

        // 关闭s3Client
        close(s3Client);
    }

}
